Play an Animation - Single Clip
What you'll learn:
- Playing an animation clip with
playAnimation() - Looping vs. one-shot playback
- Using variables to track the current clip
- Building and testing animations from Xcode
Time: ~8 minutes
Prerequisites:
- Untold Engine Studio open with an entity that has an Animation Component and at least one loaded clip (e.g.,
idle) - Access to Xcode via Scripts: Open in Xcode (toolbar button)
What We're Building
A simple animation script that:
- Plays a single clip on start
- Loops it continuously
- Shows how to trigger a one-shot clip on demand
Step 1: Create the Script
- Open Untold Engine Studio
- In the toolbar, click Scripts: Open in Xcode (blue button)
- Click the
+button and enter the script name:PlayAnimation - Click OK, then Xcode opens the Scripts package
When the script is created:
- The source file is added to your project
- You edit the script in Xcode
You'll see a template like this:
import Foundation
import UntoldEngine
import simd
extension GenerateScripts {
static func generatePlayAnimation(to dir: URL) {
// Write your script here
}
}
This script is added to GenerateScripts, which is the entry point the engine uses to discover and generate USC scripts.
Step 2: Wire Up the Script
⚠️ IMPORTANT MANUAL STEP
The editor created your script file, but you need to tell the build system to generate it.
- Click Scripts: Open in Xcode (blue button in toolbar)
- In Xcode, open GenerateScripts.swift
- Add your script to the main() function:
@main
struct GenerateScripts {
static func main() {
print("🔨 Generating USC scripts...")
let outputDir = URL(fileURLWithPath: "Generated/")
try? FileManager.default.createDirectory(at: outputDir, withIntermediateDirectories: true)
// Add this line:
generatePlayAnimation(to: outputDir)
print("✅ All scripts generated in Generated/")
}
}
Now run the GenerateScripts target (Cmd+R) to generate the .uscript files.
MPORTANT NOTES: The function name (e.g. generatePlayAnimation) MUST match the tutorial’s script Only adjust that single line per tutorial The structure, wording, and warning must remain consistent across all documents
Step 3: Write the Script
Replace the function with this complete script:
import Foundation
import UntoldEngine
import simd
extension GenerateScripts {
static func generatePlayAnimation(to dir: URL) {
let script = buildScript(name: "PlayAnimation") { s in
// Runs once when the entity starts
s.onStart()
.setVariable("idleClip", to: "idle") // Must match the clip name in the Animation Component
.setVariable("currentClip", to: "idle")
.playAnimation("idle", loop: true)
.log("Playing idle animation (looping)")
// Optional: trigger a one-shot animation with Space
s.onUpdate()
.getKeyState("space", as: "spacePressed")
.ifEqual("spacePressed", to: true) { n in
n.playAnimation("jump", loop: false) // Replace with your one-shot clip name
n.setVariable("currentClip", to: "jump")
n.log("Playing jump animation (one-shot)")
}
}
let outputPath = dir.appendingPathComponent("PlayAnimation.uscript")
try? saveUSCScript(script, to: outputPath)
print(" ✅ PlayAnimation.uscript")
}
}
Understanding the Code
playAnimation(name, loop:) - Starts an animation by name
loop: truerepeats continuously (great for idle or walk)loop: falseplays once (great for jump or attacks)
Clip names - Must match exactly what you see in the Animation Component
- Case-sensitive
- If you rename a clip in the editor, update the script too
currentClip variable - Tracks what is playing
- Useful when adding more conditions later
Step 4: Build the Script
- In Xcode, press
Cmd+Rto run the GenerateScripts target and generate the.uscript(optional:Cmd+Bfirst to verify the build). - Watch for the Xcode run output:
🔨 Generating USC scripts...
✅ PlayAnimation.uscript
✅ All scripts generated in Generated/
First build? May take 30-60 seconds to download engine dependencies. Subsequent builds are much faster.
Step 5: Attach to an Entity
- Return to Untold Engine Studio
- Select an entity that has an Animation Component
- In the Asset Library, double click on the animations you want to add to the entity, i.e.
idleandjump - In the Inspector panel, click Add Component → Script Component
- In the Asset Browser, find
PlayAnimation.uscriptunder Scripts/Generated - Double click on the
.uscript. The script will be linked to the entity
Step 6: Test It!
- Click Play in the toolbar
- The entity should immediately play the
idleclip on loop - Tap Space to trigger the one-shot clip (e.g.,
jump) - Click Stop to exit Play mode
Understanding the Output
- Looping clip runs continuously until another clip interrupts it
- One-shot clip plays once; if you need to return to idle automatically, add a timer or state check
- If nothing plays, verify the clip names match the Animation Component exactly
⚠️ Asset Note: The script only calls animations that already exist on the entity’s Animation Component. Ensure clips are loaded and named correctly.
Modify and Experiment
Try these changes to learn more:
Start with a Different Clip
.setVariable("idleClip", to: "breathing_idle")
.playAnimation("breathing_idle", loop: true)
Return to Idle After One-Shot
s.onUpdate()
.getKeyState("space", as: "spacePressed")
.ifEqual("spacePressed", to: true) { n in
n.playAnimation("jump", loop: false)
n.setVariable("currentClip", to: "jump")
}
// Simple timer to return to idle after ~1 second
.setVariable("returnTimer", to: 60.0) // frames at ~60 FPS
.ifGreater("returnTimer", than: 0.0) { n in
n.addFloat("returnTimer", literal: -1.0, as: "returnTimer")
}
.ifEqual("returnTimer", to: 0.0) { n in
n.playAnimation("idle", loop: true)
n.setVariable("currentClip", to: "idle")
}
Add a Stop Button
.getKeyState("p", as: "pPressed")
.ifEqual("pPressed", to: true) { n in
n.stopAnimation()
n.log("Animation stopped")
}
After making changes:
- In Xcode, press
Cmd+Rto rerun the GenerateScripts target and regenerate the scripts (Cmd+Boptional first). - Click Reload in the Script Component Inspector
- Test in Play mode
What You Learned
✅ Playing animation clips with playAnimation()
✅ Looping vs. one-shot playback
✅ Tracking the current clip with script variables
✅ Building, attaching, and testing animation scripts